home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
graphics
/
mfpic
/
alfatest
/
graphbase.mf
< prev
next >
Wrap
Text File
|
1994-07-20
|
19KB
|
1,053 lines
%%%
%%% File: graphbase.mf
%%%
mode_setup;
message "mfpic version 0.2.9 alpha Tue 21 July 1994";
%% Global Variables.
% when the numeric variable `graphbase' is known,
% then graphbase.mf has been input.
% (idea taken from DEK's cmbase.mf)
if known graphbase:
errmessage "You have loaded graphbase.mf more than once!";
else:
numeric graphbase;
graphbase := 1;
fi
% pen width
% in pixel coordinates
newinternal penwd;
interim penwd:=0.5pt;
% temporary path
path trash;
%% Utility Macros.
% convert text pairs list t to array p.
% best used inside a vardef.
def textpairs (suffix p) (text t) =
save p;
pair p[];
p:=0;
for a=t:
p[incr p]:=a;
endfor
enddef;
vardef floorpair(expr p) =
(floor (xpart p), floor (ypart p))
enddef;
vardef ceilingpair(expr p) =
(ceiling (xpart p), ceiling (ypart p))
enddef;
vardef hroundpair(expr p) =
(hround (xpart p), hround (ypart p))
enddef;
vardef minpair(expr u)(text t) =
pair p; numeric x, y;
p:=u;
for q=t:
x:=min(xpart p, xpart q);
y:=min(ypart p, ypart q);
p:=(x,y);
endfor;
p
enddef;
vardef maxpair(expr u)(text t) =
pair p; numeric x, y;
p:=u;
for q=t:
x:=max(xpart p, xpart q);
y:=max(ypart p, ypart q);
p:=(x,y);
endfor;
p
enddef;
%% Coordinate Conversion.
% (affine transformation)
% graph -> pixel
% beginchar defines w and h
def xconv(expr xvalue) =
((xvalue-xneg)/(xpos-xneg))*w
enddef;
def yconv(expr yvalue) =
((yvalue-yneg)/(ypos-yneg))*h
enddef;
transform ztr;
def setztr =
ztr:=identity
shifted -(xneg,yneg)
xscaled (w/(xpos-xneg))
yscaled (h/(ypos-yneg));
enddef;
def zconv (expr a) =
a transformed ztr
enddef;
%% Initial Setup.
% active_plane is the active drawing plane.
% currentpicture is unknown at this stage,
% so use a def, not a picture assignment.
def active_plane = currentpicture enddef;
def initpic =
setztr;
def active_plane = currentpicture enddef;
pickup pencircle scaled penwd;
enddef;
%% Extra Trigonometric and Hyperbolic Functions.
def acos (expr x) = angle ((x, 1+-+x)) enddef;
def asin (expr y) = angle ((1+-+y, y)) enddef;
def exp primary X = (mexp (256 * X)) enddef;
def ln primary X = (mlog (X) / 256) enddef;
vardef cosh primary X =
save temp;
temp = exp X;
(temp + 1/temp) / 2;
enddef;
vardef sinh primary X =
save temp;
temp = exp X;
(temp - 1/temp) / 2;
enddef;
def acosh (expr y) = ln (y + (y+-+1)) enddef;
def asinh (expr y) = ln (y + (y++1)) enddef;
%% Coordinate Systems and Transformations.
% Coordinate nesting.
def bcoords =
begingroup
save old_t;
transform old_t;
old_t = currenttransform;
enddef;
def ecoords =
currenttransform := old_t;
endgroup
enddef;
% Coordinate changes.
% Example: `apply_t (rotated) (theta);'.
def apply_t (text transformer) =
currenttransform := identity transformer
transformed currenttransform;
enddef;
let xslanted = slanted; % (x+sy, y).
def yslanted primary s = % (x, y+sx).
transformed
begingroup
transform T_;
origin transformed T_ = origin;
(1,0) transformed T_ = (1,s);
(0,1) transformed T_ = (0,1);
T_
endgroup
enddef;
def zslanted primary p = % (xu+yv, xv+yu), where p = (u,v).
transformed
begingroup
transform T_;
xpart T_ = ypart T_ = 0;
xxpart T_ = yypart T_ = xpart p;
xypart T_ = yxpart T_ = ypart p;
T_
endgroup
enddef;
def xyswapped =
zslanted (0,1)
enddef;
def boosted primary X = % boosts for special relativity
zslanted (cosh X, sinh X)
enddef;
% Rotate path f about point p by angle th,
% where f is in _pixel_ coordinates,
% and p and th are in _graph_ coordinates.
vardef rotatedpath(expr p,th) expr f =
f transformed inverse ztr rotatedaround (p,th) transformed ztr
enddef;
%% Bitmaps, Clipping and Rendering.
% bitmap to bitmap --- bitwise operations.
% Change a picture v to {0,1} (`monochrome') form.
% Apply this before the other monochrome operations.
def mono (suffix v) =
cull v keeping (1, infinity);
enddef;
% bitwise and.
primarydef v picand w =
begingroup
picture u; u=v+w; cull u keeping (2,2); u
endgroup
enddef;
% inclusive or.
primarydef v picor w =
begingroup
picture u; u=v+w; cull u keeping (1,2); u
endgroup
enddef;
% exclusive or.
primarydef v picxor w =
begingroup
picture u; u=v+w; cull u keeping (1,1); u
endgroup
enddef;
% (nonsymmetric) difference.
primarydef v picsub w =
begingroup
picture u; u=v-w; cull u keeping (1,1); u
endgroup
enddef;
% contour to bitmap --- clipping and filling.
% (safely filled) interior of contour c,
% where c is in graph coordinates;
% adapted from _The MFbook_'s "safefill".
vardef interior expr c =
save vs; picture vs; vs=nullpicture;
interim turningcheck:=0;
addto vs contour (c.t_) withpen nullpen;
cull vs dropping (0,0);
vs
enddef;
% derived bitmap operations.
% clip copy of picture vt to interior of cycle c,
% where c is in graph coordinates,
% return result (which is a `subpicture' of vt).
vardef clip (suffix vt) expr c =
mono (vt);
vt picand (interior c)
enddef;
% fill region inside c in picture vt,
% where c is in graph coordinates.
vardef picfill (suffix vt) expr c =
mono (vt);
vt := vt picor (interior c);
enddef;
% unfill region inside c in picture vt,
% where c is in graph coordinates.
vardef picunfill (suffix vt) expr c =
mono (vt);
vt := vt picsub (interior c);
enddef;
% reverse video of vt inside c,
% where c is in graph coordinates.
vardef picneg (suffix vt) expr c =
mono (vt);
(interior c) picsub vt
enddef;
% rendering paths --- drawing and filling.
% draw path f in picture v using current pen,
% where f is in graph coordinates.
def onepath (expr f) (suffix v) =
addto v doublepath (f.t_)
withpen currentpen;
enddef;
% drawing a path d safely in picture vt,
% where d is in graph coordinates.
% (Courtesy of Uwe Bonnes.)
newinternal minpen;
interim minpen := 0.01pt;
vardef picdraw (suffix vt) expr d =
save vs; picture vs; vs=nullpicture;
interim turningcheck:=0;
if penwd > minpen:
onepath (d, vs);
mono (vs);
fi;
addto vt also vs;
enddef;
% drawing a path d safely,
% where d is in graph coordinates.
def safedraw expr d =
picdraw (active_plane) d;
enddef;
% filling a region, the interior of c, safely,
% where c is in graph coordinates.
def safefill expr c =
if cycle c:
picfill (active_plane) c
else:
safedraw c
fi;
enddef;
% erasing a region (the interior of c) safely,
% where c is in graph coordinates.
% - really works this time -
def safeunfill expr c =
if cycle c:
picunfill (active_plane) c
else:
safedraw c
fi;
enddef;
% draw path f and return path f,
% where f is in graph coordinates.
vardef drawnpath expr f =
safedraw f;
f
enddef;
%% Shading and Hatching.
% shading routine
% in pixel coordinates
% one square dot scaled to (actual) size in x and y directions:
% size is in pixel coordinates.
def setsqdot (expr size) =
if not picture sqdot:
picture sqdot;
fi
sqdot := nullpicture;
addto sqdot
contour unitsquare
xscaled (hround (size))
yscaled (vround (size))
withpen nullpen;
enddef;
setsqdot (0.5pt);
% draw a square dot at position p in picture v,
% where p is in _graph_ coordinates.
def squaredot (expr p)(suffix v) =
addto v also (sqdot shifted (hroundpair (p.t_)));
enddef;
% calculate bounding box points (ll, ur) for path f.
% This is coordinate system independent, but it's usually
% employed when f is in pixel coordinates.
def bbox (expr f)(suffix ll, ur) =
ur := ll := point 0 of f;
pair p[];
for i=0 upto length f:
p0 := point i of f;
p1 := precontrol i of f;
p2 := postcontrol i of f;
ll := minpair (ll, p0, p1, p2);
ur := maxpair (ur, p0, p1, p2);
endfor;
% FOR TESTING ONLY: DRAW THE BOUNDING BOX:
% safedraw (rect (ll, ur));
enddef;
% shade interior of path f with dots spaced sp apart,
% where f is in _graph_ coordinates,
% and sp is in _pixel_ coordinates.
def shadepath(expr sp) expr f =
if not cycle f:
safedraw f;
elseif sp<=0:
fill f;
else:
picture v;
pair p[], ll, ur, mn;
bbox (f, ll, ur);
ll:=sp*(ceilingpair(ll/sp));
mn:=floorpair((ur-ll)/sp);
m:=xpart mn;
n:=ypart mn;
twosp:=2*sp;
v:=nullpicture;
p2:=ll;
for i=0 upto m:
p3:=p2 if odd i: +(0,sp) fi;
for j=0 upto n:
if (not odd (i+j)):
% squaredot (p3, v);
onepath (p3, v);
p3:=p3+(0,twosp);
fi;
endfor;
p2:=p2+(sp,0);
endfor;
addto active_plane
also clip(v) f;
fi;
enddef;
% hatch interior of path f with lines spaced sp apart,
% where f is in _graph_ coordinates,
% and sp is in _pixel_ coordinates.
def hatchpath(expr sp) expr f =
if not cycle f:
safedraw f;
elseif sp<=0:
fill f;
else:
picture v;
pair p[], ll, ur, mn;
bbox (f, ll, ur);
p0:=ll - (0,xpart ur - xpart ll);
p0:=sp*floorpair(p0/sp);
m:=ceiling((ypart ur + xpart ur
- ypart ll - xpart ll)/(sqrt(2)*sp));
v:=nullpicture;
p1:=(0,sqrt(2)*sp);
p2:=p0;
p3:=p2+(xpart ur - xpart ll + sp,
xpart ur - xpart ll + sp);
for i=0 upto m:
onepath (p2--p3, v);
p2:=p2+p1; p3:=p3+p1;
endfor;
addto active_plane
also clip(v) f;
p0:=ll + (xpart ur - xpart ll,
xpart ll - xpart ur);
p0:=sp*floorpair(p0/sp);
v:=nullpicture;
p2:=ll;
p2:=sp*floorpair(p2/sp);
p3:=p2+(xpart ur - xpart ll + sp,
xpart ll - xpart ur - sp);
for i=0 upto m:
onepath (p2--p3, v);
p2:=p2+p1; p3:=p3+p1;
endfor;
addto active_plane
also clip(v) f;
fi;
enddef;
%% Dots and Dashes.
% return estimated length of segment k of path f,
% using an n-piece polyline approximation.
vardef seglength(expr f, k, n)=
pair p[], q[];
p1:=0.5[point k-1 of f,postcontrol k-1 of f];
p2:=0.5[postcontrol k-1 of f,precontrol k of f];
p3:=0.5[precontrol k of f,point k of f];
for i=2 upto n:
q1:=0.5[point k-1 of f,p1];
for j=2 upto i+1:
q[j]:=0.5[p[j-1],p[j]];
p[j-1]:=q[j-1];
endfor;
p[i+2]:=0.5[p[i+1],point k of f];
p[i+1]:=q[i+1];
endfor;
l:=length(p1-(point k-1 of f));
for i=1 upto n+1:
l:=l+length(p[i+1]-p[i]);
endfor;
l:=l+length((point k of f)-p[n+2]);
l
enddef;
% draw dotted/dashed curve along path f,
% with dash length dlen and dash space slen;
% return f.
vardef dotted(expr dlen, slen) expr f =
pair p[]; numeric a[];
len:=0;
for i=1 upto length f:
a[i]:=seglength(f, i, 10);
len:=len+a[i];
endfor;
if len<dlen: safedraw f;
else:
n:=floor(len/(dlen+slen));
delta:=(len/n)-(dlen+slen);
dist:=0.5*dlen;
for i=0 upto (length f)-1:
len:=a[i+1];
forever:
exitif dist>len;
safedraw subpath
(i if dist>dlen: +(dist-dlen)/len fi, i+(dist/len))
of f;
dist:=dist+slen+delta+dlen;
endfor;
dist:=dist-len;
if dist<dlen:
safedraw subpath (i+(len+dist-dlen)/len, i+1) of f;
fi;
endfor;
fi;
f
enddef;
%% Points.
def pointd(expr ptwd,filled)(text t) =
pair p.px;
for a=t:
p.px:=a transformed ztr;
if filled: safefill else: safeunfill drawnpath fi
fullcircle scaled ptwd shifted p.px;
endfor
enddef;
%% Arrows.
% arrowheads are in pixel coordinates
boolean hfilled;
newinternal hdwdr, hdten;
interim hdwdr:=1;
interim hdten:=1;
def head(expr front, back, width, t, filled) =
pair p[], side;
side := (width/2) *
((front-back) rotated 90);
p1 := back + side;
p2 := back - side;
if filled: safefill drawnpath else: safedraw fi
p1..tension t..{front-back}(front){back-front}..tension t..p2
if filled: --cycle; fi;
enddef;
vardef headpath(expr hlen, hrot, hback) expr f=
pair p[];
p2:=point length f of f;
p1:=direction length f of f;
if p1<>(0,0):
p3:=(unitvector(p1) rotated hrot);
head(p2-(hback*p3),p2-((hlen+hback)*p3),
hdwdr,hdten,hfilled);
fi;
f
enddef;
def arrow(expr tl,hd,hlen) =
path f.px;
f.px:= (tl..hd) transformed ztr;
safedraw f.px;
trash:=headpath(hlen,0,0pt) f.px;
enddef;
%% Axes and Axis Tic Marks.
def axes(expr hlen) =
arrow((0,yneg),(0,ypos),hlen);
arrow((xneg,0),(xpos,0),hlen);
enddef;
def xmarks(expr len)(text t) =
for a=t:
safedraw (xconv(a),yconv(0)-(len/2))..
(xconv(a),yconv(0)+(len/2));
endfor;
enddef;
def ymarks(expr len)(text t) =
for a=t:
safedraw (xconv(0)-(len/2),yconv(a))..
(xconv(0)+(len/2),yconv(a));
endfor;
enddef;
%% Path Construction.
% polyline construction
def mkpoly (expr cyclic)
(suffix pts) =
for i=1 upto pts-1:
pts[i]--
endfor
pts[pts]
if cyclic:
--cycle
fi
enddef;
% smooth path construction
def mksmooth (expr cyclic)
(suffix pts) =
if cyclic:
pts[1]{pts[2]-pts[pts]}
else:
pts[1]
fi
for i=2 upto pts-1:
..pts[i]{pts[i+1]-pts[i-1]}
endfor
if cyclic:
..pts[pts]{pts[1]-pts[pts-1]}..cycle
else:
..pts[pts]
fi
enddef;
% general path construction
def mkpath(expr smooth, cyclic)
(suffix pts) =
if smooth:
mksmooth(cyclic,pts)
else:
mkpoly(cyclic,pts)
fi
enddef;
%% Upright Rectangles.
def mkrect(expr ll,ur) =
ll--(xpart ll,ypart ur)--
ur--(xpart ur,ypart ll)--cycle
enddef;
def rect(expr ll,ur) =
(mkrect(ll,ur))
enddef;
%% Curves.
vardef mkcurve(expr smooth,cyclic)
(text t) =
textpairs(p,t);
mkpath(smooth,cyclic,p)
enddef;
def curve(expr smooth,cyclic)
text t =
mkcurve(smooth,cyclic,t)
enddef;
% quadratic B-splines.
% p[] == B-spline control points,
% p in number.
vardef openqbs (text t) =
textpairs(p,t);
for i=1 upto p-2:
0.5[p[i],p[i+1]]
..controls 1/6[p[i+1],p[i]]
and 1/6[p[i+1],p[i+2]]..
endfor
0.5[p[p-1],p[p]]
enddef;
vardef closedqbs (text t) =
textpairs(p,t);
p[p+1]:=p1;
p[p+2]:=p2;
for i=1 upto p:
0.5[p[i],p[i+1]]
..controls 1/6[p[i+1],p[i]]
and 1/6[p[i+1],p[i+2]]..
endfor
cycle
enddef;
% cubic B-splines.
vardef mkopencbs (suffix b) =
for i=1 upto b-3:
(b[i]+4b[i+1]+b[i+2])/6
..controls 1/3[b[i+1],b[i+2]]
and 2/3[b[i+1],b[i+2]]..
endfor
(b[b-2]+4b[b-1]+b[b])/6
enddef;
vardef opencbs (text t) =
textpairs(b,t);
mkopencbs(b)
enddef;
vardef mkclosedcbs (suffix b) =
b[b+1]:=b1;
b[b+2]:=b2;
for i=1 upto b:
(b[i]+4b[i+1]+b[i+2])/6
..controls 1/3[b[i+1],b[i+2]]
and 2/3[b[i+1],b[i+2]]..
endfor
cycle
enddef;
vardef closedcbs (text t) =
textpairs(b,t);
mkclosedcbs(b)
enddef;
%% Path Closure.
% path f closed by line segment.
vardef closedpath expr f =
f
if not cycle f:
--cycle
fi
enddef;
% close path f in manner of mksmooth.
vardef sclosedpath expr f =
if cycle f:
f
else:
save n;
n := length f;
if n >= 2:
(point 0 of f){(point 1 of f)-(point infinity of f)}
..(subpath (1,n-1) of f)
..(point infinity of f){(point 0 of f)-(point (n-1) of f)}
..cycle
elseif n = 1:
f--cycle
else: % single point
f..cycle
fi
fi
enddef;
% path f closed by bezier.
vardef bclosedpath expr f =
f
if not cycle f:
..cycle
fi
enddef;
% conversion of Bezier segment key points, z,
% to cubic B-spline control points, b.
def ztob (suffix z, b) =
pair b[];
b := 4;
b1 = 6z1-7z2+2z3;
b2 = 2z2- z3;
b3 = - z2+2z3;
b4 = 2z2-7z3+6z4;
enddef;
% closure of path f by a cubic B-spline.
vardef cbclosedpath expr f =
if cycle f:
f
else:
pair p[];
p1 := point 0 of f;
p2 := postcontrol 0 of f;
p3 := precontrol 1 of f;
p4 := point 1 of f;
ztob(p,a);
n := length f;
p1 := point (n-1) of f;
p2 := postcontrol (n-1) of f;
p3 := precontrol infinity of f;
p4 := point infinity of f;
ztob(p,b);
b1 := b3;
b2 := b4;
b3 := a1;
b4 := a2;
f..mkopencbs(b)..cycle
fi
enddef;
%% Circles and Ellipses.
vardef mkellipse(expr center,radx,rady,
angle) =
save t;
transform t;
t:=identity xscaled (2*radx)
yscaled (2*rady) rotated angle
shifted center;
fullcircle transformed t
enddef;
def ellipse(expr center,radx,rady,
angle) =
(mkellipse(center,radx,rady,angle))
enddef;
def circle(expr center,rad) =
ellipse(center,rad,rad,0)
enddef;
%% Circular Arcs.
vardef mkarc(expr center,from,sweep)=
pair p,q;
path f;
if sweep=0: f:=from
else:
n:=floor(abs(sweep)/45)+1;
if n<3: n:=3; fi;
theta:=sweep/(n-1);
f:=p:=from;
for i=2 upto n:
p:=p rotatedabout (center,theta);
q:=p-center; q:=q rotated 90;
if theta<0: q:=-q; fi;
f:=f..p{unitvector q};
endfor;
fi;
f
enddef;
vardef arccenter(expr from,to,sweep)=
pair midpt;
if from=to:
from
else:
midpt:=(0.5)[from,to];
if (sweep mod 360)=0:
midpt
else:
disp:=cosd(sweep/2)/sind(sweep/2);
midpt+(disp*((to-from) rotated 90)/2)
fi
fi
enddef;
% point-point-sweep form of arc
vardef arcpps(expr from,to,sweep) =
pair center;
center:=arccenter(from,to,sweep);
(mkarc(center, from, sweep))
enddef;
% modified polar --
% center, angle, angle, radius
vardef arcplr(expr center,
frtheta,totheta,rad) =
pair from;
from:=center+rad*(dir frtheta);
(mkarc(center,from,
totheta-frtheta))
enddef;
% center-point-sweep form
def arccps(expr center, from, theta)=
(mkarc(center, from, theta))
enddef;
% point-point-point form
vardef arcppp(expr first, second, third)=
sweep:=2*(angle(third-second)-angle(second-first));
sweep:=sweep mod 720;
if sweep > 360: sweep:=sweep-720; fi
critical:=5;
if abs(sweep) <= critical: % center may blow out
save p;
pair p[];
p:=3;
p1:=first;
p2:=second;
p3:=third;
mkpath(true,false,p)
else:
pair m[], d[], center;
m1:=(0.5)[first,second]; d1:=(second-first) rotated 90;
m2:=(0.5)[second,third]; d2:=(third-second) rotated 90;
center = m1+whatever*d1 = m2+whatever*d2;
mkarc(center,first,sweep)
fi
enddef;
%% Polar Coordinates.
% (r, theta) -> (x, y).
def plrconv(expr a)=
((ypart a)*(dir xpart a))
enddef;
def plrpointd(expr ptwd,filled)(text t) =
pair p.px;
for a=t:
p.px:=plrconv(a) transformed ztr;
if filled: safefill else: safeunfill drawnpath fi
fullcircle scaled ptwd shifted p.px;
endfor
enddef;
vardef mkplrcurve(expr smooth,cyclic)
(text t)=
save p;
pair p[];
p:=0;
for a=t:
p[incr p]:=plrconv(a);
endfor;
mkpath(smooth,cyclic,p)
enddef;
def plrcurve(expr smooth,cyclic)
text t =
mkplrcurve(smooth,cyclic,t)
enddef;
% other figures
vardef turtle(text t)=
save p;
pair p[];
p:=0;
th:=0;
for a=t:
if p=0:
p[incr p]:=a;
else:
th:=th+(xpart a);
p[incr p]:=((ypart a)*(dir th));
p[p]:=p[p]+p[p-1]-((0,0) );
fi;
endfor;
(mkpath(false,false,p))
enddef;
%% Wedges.
vardef wedge(expr center,
frtheta,totheta,rad) =
pair from;
from:=center+rad*(dir frtheta);
(center--
mkarc(center,from,totheta-frtheta)
--cycle)
enddef;
%% Functions.
vardef mkfcn(expr smooth,bmin,bmax,bst)
(suffix bv)(text fcnpr)=
save p;
pair p[];
p:=0;
for bv=bmin step bst until bmax+(bst/2):
p[incr p]:=fcnpr;
endfor;
mkpath(smooth,false,p)
enddef;
def function(expr smooth,xmin,xmax,st)
(text fx) =
(mkfcn(smooth,xmin,xmax,st,
x,(x,fx)))
enddef;
def parafcn(expr smooth,tmin,tmax,st)
(text ft) =
(mkfcn(smooth,tmin,tmax,st,
t,ft))
enddef;
def plrfcn(expr smooth,tmin,tmax,st)
(text ft) =
(mkfcn(smooth,tmin,tmax,st,
t,((ft)*cosd(t),(ft)*sind(t))))
enddef;
%%%
%%% end graphbase.mf
%%%